
use shq_common::prelude::{get_my_pool, AuthType, ColumnRange, Permission, RowRange};
use sqlx::{Executor, Statement};


pub(super) async fn save_user_perms(user_id: u32, perms: Vec<(u32,Permission)>) -> anyhow::Result<()> {
    let mut tx = get_my_pool().begin().await?;
    let sql = "delete FROM sys_user_permission WHERE user_id = ?";
    sqlx::query(sql).bind(&user_id).execute(&mut *tx).await?;
    let stmt=tx.prepare("insert into sys_user_permission(user_id,perm_id,auth_type_ids,row_range_ids,column_range_ids) values(?,?,?,?,?)").await?;
    for (id,pope) in perms {
        let perm_type_ids_str = vec_to_str(pope.auth_types);
        let row_range_ids_str = vec_to_str(pope.row_ranges);
        let column_range_ids_str = vec_to_str(pope.column_ranges);
        stmt.query()
            .bind(&user_id)
            .bind(&id)
            .bind(&perm_type_ids_str)
            .bind(&row_range_ids_str)
            .bind(&column_range_ids_str)
            .execute(&mut *tx)
            .await?;
    }
    tx.commit().await?;
    Ok(())
}
pub(super) async fn save_role_perms(role_id: u32, perms: Vec<(u32,Permission)>) -> anyhow::Result<()> {
    let mut tx = get_my_pool().begin().await?;
    let sql = "delete FROM sys_role_permission WHERE role_id = ? ";
    sqlx::query(sql).bind(&role_id).execute(&mut *tx).await?;
    let stmt=tx.prepare("insert into sys_role_permission(role_id,perm_id,auth_type_ids,row_range_ids,column_range_ids) values(?,?,?,?,?)").await?;
    for (id,pope) in perms {
        let perm_type_ids_str = vec_to_str(pope.auth_types);
        let row_range_ids_str = vec_to_str(pope.row_ranges);
        let column_range_ids_str = vec_to_str(pope.column_ranges);
        stmt.query()
            .bind(&role_id)
            .bind(&id)
            .bind(&perm_type_ids_str)
            .bind(&row_range_ids_str)
            .bind(&column_range_ids_str)
            .execute(&mut *tx)
            .await?;
    }
    tx.commit().await?;
    Ok(())
}
pub(crate) async fn save_user_roles(user_id: u32, role_ids: &[u32]) -> anyhow::Result<()> {
    let mut tx = get_my_pool().begin().await?;
    let sql = "delete FROM sys_user_role WHERE user_id = ? ";
    sqlx::query(sql).bind(&user_id).execute(&mut *tx).await?;
    let stmt = tx
        .prepare("insert into sys_user_role(user_id,role_id) values(?,?)")
        .await?;
    for role_id in role_ids {
        stmt.query()
            .bind(&user_id)
            .bind(&role_id)
            .execute(&mut *tx)
            .await?;
    }
    tx.commit().await?;
    Ok(())
}
pub(crate) async fn save_role_users(role_id: u32, user_ids: &[u32]) -> anyhow::Result<()> {
    let mut tx = get_my_pool().begin().await?;
    let sql = "delete FROM sys_user_role WHERE role_id = ?";
    sqlx::query(sql).bind(&role_id).execute(&mut *tx).await?;
    let stmt = tx
        .prepare("insert into sys_user_role(role_id,user_id) values(?,?)")
        .await?;
    for user_id in user_ids {
        stmt.query()
            .bind(&role_id)
            .bind(&user_id)
            .execute(&mut *tx)
            .await?;
    }
    tx.commit().await?;
    Ok(())
}

pub(super) async fn del_role_by_id(role_id: u32) -> anyhow::Result<()> {
    let mut tx = get_my_pool().begin().await?;
    let sql = "delete FROM sys_role_permission WHERE role_id = ?";
    sqlx::query(sql).bind(&role_id).execute(&mut *tx).await?;
    let sql = "delete FROM sys_user_role WHERE role_id = ?";
    sqlx::query(sql).bind(&role_id).execute(&mut *tx).await?;
    tx.commit().await?;
    Ok(())
}

pub(super) async fn del_user_by_id(user_id: u32) -> anyhow::Result<()> {
    let mut tx = get_my_pool().begin().await?;
    let sql = "delete FROM sys_user_permission WHERE user_id = ?";
    sqlx::query(sql).bind(&user_id).execute(&mut *tx).await?;
    let sql = "delete FROM sys_user_role WHERE user_id = ?";
    sqlx::query(sql).bind(&user_id).execute(&mut *tx).await?;
    tx.commit().await?;
    Ok(())
}

pub(crate) fn vec_to_str<T: Into<u8>>(vec: Vec<T>) -> String {
    let mut s = String::new();
    for v in vec {
        s.push_str(&v.into().to_string());
        s.push(',');
    }
    s.pop();
    s
}
pub(crate) fn str_to_auth_type_vec(s: Option<&str>) -> anyhow::Result<Vec<AuthType>> {
    if let Some(s) = s {
        if s.is_empty() {
            return Ok(Vec::new());
        }
        let mut auth_types:Vec<AuthType> = Vec::new();
        for at in s.split(',') {
            let at = at.parse::<u8>()?;
            auth_types.push(at.into());
        }
        Ok(auth_types)
    } else {
        Ok(Vec::new())
    }
}
pub(crate) fn str_to_row_range_vec(s: Option<&str>) -> anyhow::Result<Vec<RowRange>> {
    if let Some(s) = s {
        if s.is_empty() {
            return Ok(Vec::new());
        }
        let mut auth_types:Vec<RowRange> = Vec::new();
        for rr in s.split(',') {
            let rr = rr.parse::<u8>()?;
            auth_types.push(rr.into());
        }
        Ok(auth_types)
    } else {
        Ok(Vec::new())
    }
}
pub(crate) fn str_to_column_range_vec(s: Option<&str>) -> anyhow::Result<Vec<ColumnRange>> {
    if let Some(s) = s {
        if s.is_empty() {
            return Ok(Vec::new());
        }
        let mut auth_types:Vec<ColumnRange> = Vec::new();
        for cr in s.split(',') {
            let cr = cr.parse::<u8>()?;
            auth_types.push(cr.into());
        }
        Ok(auth_types)
    } else {
        Ok(Vec::new())
    }
}
